DataTable = DataTable or Class("DataTable", EventDispatcher)

---@diagnostic disable-next-line: duplicate-set-field
function DataTable:ctor(template, dataManager)
    EventDispatcher.ctor(self)
    self._template = template
    self.templateId = template.id
    self._datas = {}
    self._dirtyEvents = {}
    self._dataManager = dataManager
    self.id = self._dataManager:createInstanceId()
    for id, setting in pairs(template._dataSettings) do
        self._datas[id] = setting.defaultValue
    end
    for argId, arg in pairs(template._formulaArgs) do
        self:addFormulaArg(arg)
    end
end

function DataTable:addDirtyEventSelf(arg, listener, depth)
    local id = arg.argPath[depth]
    self._dirtyEvents[id] = self._dirtyEvents[id] or {}
    table.insert(self._dirtyEvents[id], {
        arg = arg,
        depth = depth,
        listener = listener
    })
end

function DataTable:addDirtyEvent(arg, listener, depth)
    self:addDirtyEventSelf(arg, listener, depth)
    if #arg.argPath > depth then
        local child = self:get(arg.argPath[depth])
        child:addDirtyEventSelf(arg, listener, depth + 1)
    end
end

function DataTable:addFormulaArg(arg)
    local root = arg.rootSelf and self._dataManager.root or self
    root:addDirtyEvent(arg, self, 1)
end

function DataTable:addData(setting)
    self._datas[setting.id] = setting.defaultValue or 0
    if setting.dataType == DataType.DataTable then
        local tpl = self._dataManager:getDataTemplate(setting.templateId)
        self._datas[setting.id] = tpl:createDataTable().id
    end
end

function DataTable:get(id)
    local setting = self._template._dataSettings[id]
    if setting.dataType == DataType.DataTable then
        local cId = self._datas[id]
        if cId ~= 0 then
            local tplId = setting.templateId
            return self._dataManager:getDataTable(tplId, cId)
        end
    else
        return self._datas[id]
    end
end

function DataTable:addList(elementType)
    local dataList = DataList.new(elementType, self._dataManager)
    return dataList.id
end

function DataTable:set(dataId, value)
    local old = self._datas[dataId]
    self._datas[dataId] = value
    self:_doDirtyEvents(dataId)
    local dataType = self._template._dataSettings[dataId].dataType
    if dataType == DataType.DataTable then
        local events = self._dirtyEvents[dataId]
        for _, event in ipairs(events) do
            old:removeDirtyEvent(event.argId)
        end
    end
end

function DataTable:removeDirtyEvent(argId)
    for dataId, events in pairs(self._dirtyEvents) do
        for i = #events, 1, -1 do
            local event = events[i]
            if event.argId == argId then
                table.remove(events, i)
                if self:getDataType(dataId) == DataType.DataTable then
                    self:get(dataId):removeDirtyEvent(argId)
                end
            end
        end
    end
end

function DataTable:_doDirtyEvents(dataId)
    if self._dirtyEvents[dataId] then
        for _, node in ipairs(self._dirtyEvents[dataId]) do
            node.listener:setDirty(node.arg.dataId)
        end
    end
end

-- 先做直接刷新，后续添加刷新模式
function DataTable:setDirty(id)
    local setting = self._template._dataSettings[id]
    self._datas[id] = setting.calculator(self)
    self:_doDirtyEvents(id)
end

-- 根据公式分配的argId,获取对应的值
function DataTable:getArg(argId)
    local arg = self._template:getArgInfo(argId)
    local root = arg.rootSelf and self._dataManager.root or self
    local path = arg.argPath
    for i = 1, #path do
        local id = path[i]
        if not root then
            return arg.defaultValue
        end
        root = root:get(id)
    end
    return root
end
